package admin;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.NoSuchElementException;
import java.util.Scanner;
import javax.xml.rpc.ServiceException;

import COMA_API.*;


public class ImportFile {
	final int USER_ID = 1;
	final int CUR_PAGE = 0;
	final int PAGE_SIZE = 100000;

	ServiceCOMA_APISoap service = null;
	
	Agreement[] allAgreements = null;
	Producer[] allProducers = null;
	Asset[] allAssets = null;
	AssetType[] allAssetTypes = null;
	EventType[] allEventTypes = null;
	Language[] allLanguage = null;
	FileType[] allFileTypes = null;
	Content[] allContent = null;
	Rights[] allRights = null;
	Party[] allParties = null;
	Profile[] allProfiles = null;
	Method[] allMethods = null;
	
	ArrayList<String> lines = null;
	
	public ImportFile(ServiceCOMA_APISoap service, ArrayList<String> lines){
		this.service = service;
		this.lines = lines;
	}
	
	public void processImport() throws ParserException, RemoteException, ServiceException{
		initCache();
		System.out.println("Cache initiated.");
		
		Scanner scanner = null;
		for(int i = 0; i < lines.size(); i++){
			scanner = new Scanner(lines.get(i));
			scanner.useDelimiter("\\|");
			if(lines.get(i).startsWith(Constants.IMPORT_CONTENT_AGREEMENT) ){
				try{
					importContentAgreemen(scanner);
				} catch(NoSuchElementException  e){
					throw new ParserException("Line: "+ lines.get(i) + ", " + e.getMessage());
				}
			} else if(lines.get(i).startsWith(Constants.CONFIGURE_AGREEMENT) ){
				configureAgreement(scanner);
			} else if(lines.get(i).startsWith(Constants.ADD_PARTY) ){
				addParty(scanner);
			} else {
				throw new ParserException("Invalid input, line: " +lines.get(i));
			}
		}
	}

	String translatePipe(String in){
		return in.replaceAll("\\(pipe\\)", "|");
	}
	
	void addParty(Scanner lineScanner) throws RemoteException, ServiceException, ParserException{
		// Parse line
		// # ADD_PARTY|<name>|<language>|<CIF>|<method (start pattern)>|<URL>|<description>|<profile>|<isLicensee>
		initCache();
		lineScanner.next(); // First comes ADD, don't care
		String name = lineScanner.next().trim();
		String countryCode = lineScanner.next().trim();
		String cif = lineScanner.next().trim();
		String method = translatePipe(lineScanner.next().trim());
		String url = lineScanner.next().trim();
		String description = lineScanner.next().trim();
		String profile = translatePipe(lineScanner.next().trim());
		boolean isLicensee = lineScanner.nextBoolean();
		
		// Look up id's
		int methodId = findMethodStartPattern(method);
		int profileId = findProfile(profile);
		
		// Check duplicate name
		try {
			/* YES, this according to design,
			 * findParty() will throw NoSuchElementException, that's our way out of this,
			 * else throw ServiceExcption. */
			findParty(name);
			throw new ServiceException("Failed to create Party, '" + name +"'. Party allready exists.");
		} catch(NoSuchElementException e){
			// Do nothing.
		}

		// Perform import
		Response response = service.party_ADD(USER_ID, name, countryCode, cif, methodId, url, description, profileId, isLicensee);
		Integer newId = (Integer)response.getComaobject();
		if(newId < 1 ){
			throw new ServiceException("Failed to create Party, '" + name +"'.");
		}
		allParties = null; // Force reload next time
		System.out.println("Party '" + name + "' created, id=" + newId);
	}

	int findMethodStartPattern(String name) throws ServiceException{
		int id = 0;
		for(int i = 0; i < allMethods.length; i++){
			if(allMethods[i].getValue().startsWith(name) == true){
				id = allMethods[i].getId();
			}
		}
		if(id == 0){
			throw new ServiceException("Failed to find Method, '" + name +"'.");
		}
		return id;
	}
	
	int findProfile(String name) throws ServiceException{
		int id = 0;
		for(int i = 0; i < allProfiles.length; i++){
			if(allProfiles[i].getValue().equals(name) == true){
				id = allProfiles[i].getId();
			}
		}
		if(id == 0){
			throw new ServiceException("Failed to find Profile, '" + name +"'.");
		}
		return id;
	}

	void importContentAgreemen(Scanner lineScanner) throws RemoteException, ServiceException, ParserException{
		// Parse line
		lineScanner.next(); // First comes ADD, don't care
		String agreement = lineScanner.next().trim();
		String producer = lineScanner.next().trim();
		String assetType = lineScanner.next().trim();
		String eventType = lineScanner.next().trim();
		String assetLanguage = lineScanner.next().trim();
		String contentLanguage = lineScanner.next().trim();
		String fileType = lineScanner.next().trim();
		boolean inStorage = lineScanner.nextBoolean();
		boolean inPackage = lineScanner.nextBoolean();
		String contentDescription = lineScanner.next().trim();

		// Perform import
		int agreementId = importAgreement(agreement);
		int producerId = importProducer(producer);
		int assetId = importAsset(producerId, assetType, eventType, assetLanguage);
		importContent(assetId, fileType, contentLanguage, inStorage, inPackage, contentDescription);
		String rightName = producer + ", " + assetType + "-" + assetLanguage + "-" + eventType;
		importRights(agreementId, assetId, rightName);
	}
	
	int importAgreement(String agreement) throws RemoteException, ServiceException, ParserException{
		initCache();

		//Search for Agreement
		int id = 0;
		try  {
			id = findAgreement(agreement).getId();
			System.out.println("Found Ageement '" + agreement + "', id=" + id);
		} catch(NoSuchElementException e){
			// If not found, create one.
			Response response = service.agreement_ADD(USER_ID, agreement);
			Integer newId = (Integer)response.getComaobject();
			if(newId < 1 ){
				throw new ServiceException("Failed to create Agreement, '" + agreement +"'.");
			}
			System.out.println("Agreement '" + agreement + "' created, id=" + newId);
			id = newId.intValue();
			allAgreements = null; // Force reload next time
		}
		return id;
	}

	Agreement findAgreement(String name) throws ServiceException, NoSuchElementException{
		Agreement agreement = null;
		for(int i = 0; i < allAgreements.length; i++){
			if(allAgreements[i].getName().equals(name) == true){
				if(agreement != null){
					throw new ServiceException("Several Agreement with same name exist, '" + name +"'.");
				}
				agreement = allAgreements[i];
			}
		}
		if(agreement == null){
			throw new NoSuchElementException("Agreement '" + name + "' not found.");
		}
		return agreement;
	}

	int importProducer(String producer) throws RemoteException, ServiceException{
		initCache();
		
		//Search for Producer
		int id = 0;
		for(int i = 0; i < allProducers.length && id == 0; i++){
			if(allProducers[i].getName().equals(producer) == true){
				id = allProducers[i].getId();				
			}
		}

		// Do we need to create the Producer?
		if(id == 0){
			Response response = service.producer_ADD(USER_ID, producer);
			Integer newId = (Integer)response.getComaobject();
			if(newId < 1 ){
				throw new ServiceException("Failed to create Producer, '" + producer +"'.");
			}
			System.out.println("Producer '" + producer + "' created, id=" + newId);
			id = newId.intValue();
			allProducers = null; // Force reload next time
		} else {
			System.out.println("Found Producer '" + producer + "', id=" + id);
		}
		return id;
	}

	int importAsset(int producerId, String assetType, String eventType, String language) throws RemoteException, ServiceException, ParserException{
		initCache();

		//Search for AssetType
		int assetTypeId = 0;
		for(int i = 0; i < allAssetTypes.length && assetTypeId == 0; i++){

			if(allAssetTypes[i].getName().equals(assetType) == true){
				assetTypeId = allAssetTypes[i].getId();
			}
		}
		if(assetTypeId == 0){
			throw new ParserException("AssetType not found, name= " + assetType);
		}

		//Search for Language
		int languageId = 0;
		for(int i = 0; i < allLanguage.length && languageId == 0; i++){

			if(allLanguage[i].getCode().equals(language) == true){
				languageId = allLanguage[i].getId();
			}
		}
		if(languageId == 0){
			throw new ParserException("Language not found, name= " + language);
		}
		
		//Search for EventType
		int eventTypeId = 0;
		for(int i = 0; i < allEventTypes.length && eventTypeId == 0; i++){

			if(allEventTypes[i].getName().equals(eventType) == true){
				eventTypeId = allEventTypes[i].getId();		
			}
		}
		if(eventTypeId == 0){
			throw new ParserException("EventType not found, name= " + eventType);
		}

		//Search for Asset
		int id = 0;
		for(int i = 0; i < allAssets.length && id == 0; i++){
			if(allAssets[i].getAssettype_id() == assetTypeId && allAssets[i].getEventtype_id() == eventTypeId
					&& allAssets[i].getLanguage_id() == languageId && allAssets[i].getProducer_id() == producerId){
				id = allAssets[i].getId();
			}
		}

		// Do we need to create the Asset?
		String name = assetType + "-" + language + "-" + eventType;
		if(id == 0){
			Response response = service.asset_ADD(USER_ID, assetTypeId, eventTypeId, languageId, name, producerId);
			Integer newId = (Integer)response.getComaobject();
			if(newId < 1 ){
				throw new ServiceException("Failed to create Asset, '" + name +"'.");
			}
			System.out.println("Asset '" + name + "' created, id " + newId);
			id = newId.intValue();
			allAssets = null; // Force reload next time
		} else {
			System.out.println("Found Asset '" + name + "', id=" + id);
		}
		return id;
	}

	void importContent(int assetId, String fileType, String language, boolean inStorage, boolean inPackage, String description) throws RemoteException, ServiceException, ParserException{
		if(fileType.equals("-") == true){
			return;
		}
		// Populate cache
		initCache();

		//Search for FileType
		int fileTypeId = 0;
		for(int i = 0; i < allFileTypes.length && fileTypeId == 0; i++){
			if(allFileTypes[i].getName().equals(fileType) == true){
				fileTypeId = allFileTypes[i].getId();
			}
		}
		if(fileTypeId == 0){
			throw new ParserException("AssetType not found, name= " + fileType);
		}

		//Search for Language
		int languageId = 0;
		for(int i = 0; i < allLanguage.length && languageId == 0; i++){
			if(allLanguage[i].getCode().equals(language) == true){
				languageId = allLanguage[i].getId();
			}
		}
		if(languageId == 0){
			throw new ParserException("Language not found, name= " + language);
		}

		//Search for Content
		int id = 0;
		for(int i = 0; i < allContent.length && id == 0; i++){
			if(allContent[i].getAsset_id() == assetId
					&& allContent[i].getFiletype_id() == fileTypeId
					&& allContent[i].getLanguage_id() == languageId
					&& allContent[i].getDescription().equals(description)) {
				id = allContent[i].getId();
			}
		}

		// Do we need to create the Producer?
		String name = fileType + "-" + language;
		if(id == 0){
			Response response = service.content_ADD(USER_ID, fileTypeId, languageId, description, "na", assetId, inStorage, inPackage);
			Integer newId = (Integer)response.getComaobject();
			if(newId < 1 ){
				throw new ServiceException("Failed to create Content, '" + name +"'.");
			}
			System.out.println("Content '" + name + "' created, id " + newId);
			allContent = null; // Force reload next time
		} else {
			System.out.println("Found Content '" + name + "', id=" + id);
		}
	}

	void importRights(int agreementId, int assetId, String name) throws RemoteException, ServiceException, ParserException{
		initCache();
		
		//Search for Rights
		int id = 0;
		for(int i = 0; i < allRights.length && id == 0; i++){
			if(allRights[i].getAsset_id() == assetId
					&& allRights[i].getAgreement_id() == agreementId){
				id = allRights[i].getId();
			}
		}

		// Do we need to create the Right?
		if(id == 0){
			Response response = service.rights_ADD(USER_ID, assetId, agreementId, name);
			Integer newId = (Integer)response.getComaobject();
			if(newId < 1 ){
				throw new ServiceException("Failed to create Right, '" + name +"'.");
			}
			System.out.println("Right '" + name + "' created, id " + newId);
			allRights = null; // Force reload next time
		} else {
			System.out.println("Found Rights '" + name + "', id=" + id);
		}
	}
	
	void initCache() throws RemoteException{
		if(allAssets == null){
			allAssets = (Asset[]) service.asset_GET_LIST(USER_ID, CUR_PAGE, PAGE_SIZE).getComaobject();
		}
		if(allAgreements == null){
			allAgreements = (Agreement[]) service.agreement_GET_LIST(USER_ID, CUR_PAGE, PAGE_SIZE).getComaobject();
		}
		if(allRights == null){
			allRights = (Rights[]) service.rights_GET_LIST(USER_ID, CUR_PAGE, PAGE_SIZE).getComaobject();
		}
		if(allAssetTypes == null){
			allAssetTypes = (AssetType[]) service.assetType_GET_LIST(USER_ID, CUR_PAGE, PAGE_SIZE).getComaobject();
		}
		if(allEventTypes == null){
			allEventTypes = (EventType[]) service.eventType_GET_LIST(USER_ID, CUR_PAGE, PAGE_SIZE).getComaobject();
		}
		if(allLanguage == null){
			allLanguage = (Language[]) service.language_GET_LIST(USER_ID, CUR_PAGE, PAGE_SIZE).getComaobject();
		}
		if(allContent == null){
			System.gc();
			allContent = (Content[]) service.content_GET_LIST(USER_ID, CUR_PAGE, PAGE_SIZE).getComaobject();
		}
		if(allFileTypes == null){
			allFileTypes = (FileType[]) service.fileType_GET_LIST(USER_ID, CUR_PAGE, PAGE_SIZE).getComaobject();
		}
		if(allProducers == null){
			allProducers = (Producer[]) service.producer_GET_LIST(USER_ID, CUR_PAGE, PAGE_SIZE).getComaobject();
		}
		if(allParties == null){
			allParties = (Party[]) service.party_GET_LIST(USER_ID, CUR_PAGE, PAGE_SIZE).getComaobject();
		}
		if(allProfiles == null){
			allProfiles = (Profile[]) service.profile_GET_LIST(USER_ID, CUR_PAGE, PAGE_SIZE).getComaobject();
		}
		if(allMethods == null){
			allMethods = (Method[]) service.method_GET_LIST(USER_ID, CUR_PAGE, PAGE_SIZE).getComaobject();
		}
	}
	
	void configureAgreement(Scanner lineScanner) throws RemoteException, ServiceException{
		initCache();

		// Parse line
		// CONFIGURE_AGREEMENT|<Agreement>|<Owner(Party)>|<Licensee(Party)>| ...
		lineScanner.next(); // First comes CONFIGURE.., don't care
		String agreement = lineScanner.next().trim();
		ArrayList<Party> allNewLicensees = new ArrayList<Party>(20);
		while(lineScanner.hasNext() == true){
			allNewLicensees.add(findParty(lineScanner.next().trim()));
		}

		Agreement foundAgreement = findAgreement(agreement);
		Party[] allRelatedParties = (Party[])service.party_GET_LIST_BY_AGREEMENT_ID(USER_ID,
				foundAgreement.getId(), CUR_PAGE, PAGE_SIZE).getComaobject();

		ArrayList<Party> licenseesToAdd = new ArrayList<Party>(20);
		int removedItems = 0;
		for(int n = 0; n < allNewLicensees.size(); n++){
			for(int i = 0; i < allRelatedParties.length; i++){
				if(allRelatedParties[i].getId() == allNewLicensees.get(n).getId()) {
					removedItems++;
				} else {
					licenseesToAdd.add(allNewLicensees.get(n));
				}
			}
			if(allRelatedParties.length == 0){
				licenseesToAdd.add(allNewLicensees.get(n));
			}
		}

		if(removedItems < allRelatedParties.length){
			// We need to create an new Agreement
			throw new ServiceException("Implementation missing.");
		} else {
			// Append Agreements
			for(int i = 0; i < licenseesToAdd.size(); i++){
				Response response = service.agreementParty_ADD(USER_ID, foundAgreement.getId(), licenseesToAdd.get(i).getId());
				
				Integer newId = (Integer)response.getComaobject();
				if(newId < 1 ){
					throw new ServiceException("Failed to connect Party to Agreement, " + response.getErrorReturned());
				}
			}
		}
		System.out.println("Agreement '" + agreement + "' configured.");
	}
	
	Party findParty(String name) throws ServiceException{
		Party party = null;
		for(int i = 0; i < allParties.length; i++){
			if(allParties[i].getName().equals(name) == true){
				if(party != null){
					throw new ServiceException("Several Parties with same name exist, '" + name +"'.");
				}
				party = allParties[i];
			}
		}
		if(party == null){
			throw new NoSuchElementException("Party '" + name + "' not found.");
		}
		return party;
	}

}
